﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YJKRevitBase.WinForm;
using YJKRevitView;
using YJKPresentation.CommonUnit;

namespace YJKRevitColumn.ColumnModule
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	internal class CmdBreakColumnByLevel : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			CmdViewType types = (CmdViewType)127;
			if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			this.m_cmdData = cmdData;
			this.m_doc = cmdData.Application.ActiveUIDocument.Document;
			this.m_selection = cmdData.Application.ActiveUIDocument.Selection;
			RevitVersionFuncs.ClearSelection(this.m_selection);
			if (CmdBreakColumnByLevel._hWndRevit == null)
			{
				CmdBreakColumnByLevel._hWndRevit = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
			}
			this.InitLevelList();
			BreakColumnByLevelForm breakColumnByLevelForm = new BreakColumnByLevelForm(cmdData, this.m_levels);
			breakColumnByLevelForm.Show(CmdBreakColumnByLevel._hWndRevit);
			int wMsg = 7;
			CmdBreakColumnByLevel.SendMessage(CmdBreakColumnByLevel._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			Transaction transaction = new Transaction(this.m_doc, "按层分柱");
			Result result;
			try
			{
				for (;;)
				{
					transaction.Start();
					ColumnFilter columnFilter = new ColumnFilter();
					IList<Element> list = null;
					try
					{
						list = this.m_selection.PickElementsByRectangle(columnFilter, "请框选需要打断的柱子");
					}
					catch
					{
						transaction.RollBack();
						breakColumnByLevelForm.Close();
						result = Autodesk.Revit.UI.Result.Succeeded;
						break;
					}
					List<FamilyInstance> list2 = new List<FamilyInstance>();
					foreach (Element element in list)
					{
						list2.Add(element as FamilyInstance);
					}
					if (list2.Count == 0)
					{
						transaction.RollBack();
					}
					else
					{
						List<Level> list3 = new List<Level>();
						foreach (int index in breakColumnByLevelForm.GetSelectLevelIndex())
						{
							list3.Add(this.m_levels.GetByIndex(index) as Level);
						}
						int num = 0;
						foreach (FamilyInstance column in list2)
						{
							num += this.BreakColumn(list3, column);
						}
						if (num == 0)
						{
							transaction.RollBack();
							YJKMessageBox.Show("当前选择的柱子无需分层。");
						}
						else
						{
							transaction.Commit();
						}
					}
				}
			}
			catch (Exception ex)
			{
				string message2 = ex.Message;
				transaction.RollBack();
				breakColumnByLevelForm.Close();
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private int BreakColumn(List<Level> levels, FamilyInstance column)
		{
			Level level = null;
			Level level2 = null;
			try
			{
				ElementId elementId = column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).AsElementId();
				ElementId elementId2 = column.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).AsElementId();
				level = (this.m_doc.GetElement(elementId) as Level);
				level2 = (this.m_doc.GetElement(elementId2) as Level);
			}
			catch
			{
				return 0;
			}
			double num = column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).AsDouble();
			double num2 = column.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).AsDouble();
			double num3 = level.Elevation + num;
			double num4 = level2.Elevation + num2;
			List<Level> list = new List<Level>();
			foreach (Level level3 in levels)
			{
				if (Math.Round(num3, 2) < Math.Round(level3.Elevation, 2) && Math.Round(level3.Elevation, 2) < Math.Round(num4, 2))
				{
					list.Add(level3);
				}
			}
			if (list.Count == 0)
			{
				return 0;
			}
			List<Element> wallsJoinedElement = this.GetWallsJoinedElement(column);
			bool bColumnCutWall = true;
			foreach (Element element in wallsJoinedElement)
			{
                int integerValue = column.Category.Id.IntegerValue;
				if (-2000100 == integerValue && JoinGeometryUtils.IsCuttingElementInJoin(this.m_doc, element, column))
				{
					bColumnCutWall = false;
				}
			}
			List<ElementId> elementAttachedColumn = this.GetElementAttachedColumn(column);
			Level level4 = level;
			Level level5 = level2;
			for (int i = 0; i < list.Count; i++)
			{
				int elementCount = MirrorOperater.GetElementCount(this.m_doc);
				ICollection<ElementId> source = ElementTransformUtils.CopyElement(this.m_doc, column.Id, XYZ.Zero);
				FamilyInstance familyInstance = this.m_doc.GetElement(source.ElementAt(0)) as FamilyInstance;
				List<ElementId> elementsIdAfter = MirrorOperater.GetElementsIdAfter(elementCount, this.m_doc);
				level5 = list[i];
				this.RemoveElementsExceedColumn(num3, level5.Elevation, familyInstance, elementsIdAfter);
				if (i > 0)
				{
					familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(level4.Id);
					familyInstance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(0);
				}
				familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(level5.Id);
				familyInstance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).Set(0);
				foreach (Element element2 in wallsJoinedElement)
				{
					this.JoinTwoElements(familyInstance, element2, bColumnCutWall);
				}
				level4 = level5;
				num3 = level4.Elevation;
			}
			this.RemoveElementsExceedColumn(num3, num4, column, elementAttachedColumn);
			column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).Set(level4.Id);
			column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).Set(0);
			foreach (Element element3 in wallsJoinedElement)
			{
				this.JoinTwoElements(column, element3, bColumnCutWall);
			}
			return list.Count;
		}

		private List<ElementId> GetElementAttachedColumn(FamilyInstance column)
		{
			List<ElementId> list = new List<ElementId>();
			IEnumerable<Element> enumerable = new FilteredElementCollector(this.m_doc).OfClass(typeof(FamilyInstance)).ToElements();
			ICollection<Element> collection = new FilteredElementCollector(this.m_doc).OfClass(typeof(Opening)).ToElements();
			foreach (Element element in enumerable)
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				if (familyInstance != null && familyInstance.Host != null && familyInstance.Host.Id == column.Id)
				{
					list.Add(element.Id);
				}
			}
			foreach (Element element2 in collection)
			{
				Opening opening = element2 as Opening;
				if (opening != null && opening.Host != null && opening.Host.Id == column.Id)
				{
					list.Add(element2.Id);
				}
			}
			return list;
		}

		private List<Element> GetAssociateElementByColumn(FamilyInstance column, List<Element> elements)
		{
			List<Element> list = new List<Element>();
			foreach (Element element in elements)
			{
				FamilyInstance familyInstance = element as FamilyInstance;
				if (familyInstance != null && familyInstance.Host != null && familyInstance.Host.Id == column.Id)
				{
					list.Add(familyInstance);
				}
			}
			return list;
		}

		private void RemoveElementsExceedColumn(double baseLevelValue, double topLevelValue, FamilyInstance column, List<ElementId> ids)
		{
			foreach (ElementId elementId in ids)
			{
				if (!(elementId == column.Id))
				{
					Element element = this.m_doc.GetElement(elementId);
					FamilyInstance familyInstance = element as FamilyInstance;
					if (familyInstance != null)
					{
						ElementId elementId2 = familyInstance.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).AsElementId();
						double elevation = (this.m_doc.GetElement(elementId2) as Level).Elevation;
						double num = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).AsDouble();
						double num2 = familyInstance.get_Parameter(BuiltInParameter.INSTANCE_HEAD_HEIGHT_PARAM).AsDouble();
						num += elevation;
						num2 += elevation;
						if (num >= baseLevelValue && num <= topLevelValue)
						{
							if (num2 < baseLevelValue)
							{
								continue;
							}
							if (num2 > topLevelValue)
							{
								continue;
							}
						}
						else
						{
							this.m_doc.Delete(element.Id);
						}
					}
					Opening opening = element as Opening;
					if (opening != null)
					{
						List<double> list = new List<double>();
						foreach (object obj in opening.BoundaryCurves)
						{
							Curve curve = (Curve)obj;
							list.Add(curve.GetEndPoint(0).Z);
							list.Add(curve.GetEndPoint(1).Z);
						}
						double num3 = list[0];
						foreach (double num4 in list)
						{
							if (num4 < num3)
							{
								num3 = num4;
							}
						}
						if (num3 < baseLevelValue || num3 >= topLevelValue)
						{
							this.m_doc.Delete(element.Id);
						}
					}
				}
			}
		}

		private void InitLevelList()
		{
			FilteredElementIterator elementIterator = new FilteredElementCollector(this.m_doc).OfClass(typeof(Level)).GetElementIterator();
			elementIterator.Reset();
			while (elementIterator.MoveNext())
			{
				Element element = elementIterator.Current;
				Level level = element as Level;
				if (level != null)
				{
					this.m_levels.Add(level.Elevation, level);
				}
			}
		}

		private List<Element> GetWallsJoinedElement(Element column)
		{
			List<Element> list = new List<Element>();
			foreach (ElementId elementId in JoinGeometryUtils.GetJoinedElements(this.m_doc, column))
			{
				Element element = this.m_doc.GetElement(elementId);
				list.Add(element);
			}
			return list;
		}

		private void JoinTwoElements(Element column, Element element, bool bColumnCutWall)
		{
			Wall wall = element as Wall;
			if (wall != null && !this.IsColumnLevelInWall(column as FamilyInstance, wall))
			{
				if (JoinGeometryUtils.AreElementsJoined(this.m_doc, column, wall))
				{
					JoinGeometryUtils.UnjoinGeometry(this.m_doc, column, wall);
				}
				return;
			}
			Floor floor = element as Floor;
			if (floor != null)
			{
				ElementId elementId = floor.get_Parameter(BuiltInParameter.LEVEL_PARAM).AsElementId();
				ElementId elementId2 = column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).AsElementId();
				if (elementId != elementId2)
				{
					if (JoinGeometryUtils.AreElementsJoined(this.m_doc, column, floor))
					{
						JoinGeometryUtils.UnjoinGeometry(this.m_doc, column, floor);
					}
					return;
				}
			}
			if (!JoinGeometryUtils.AreElementsJoined(this.m_doc, column, element))
			{
				JoinGeometryUtils.JoinGeometry(this.m_doc, column, element);
			}
			if (bColumnCutWall)
			{
				this.SetJoinOrder(column, element);
				return;
			}
			this.SetJoinOrder(element, column);
		}

		private void SetJoinOrder(Element column, Element wall)
		{
			if (!JoinGeometryUtils.IsCuttingElementInJoin(this.m_doc, column, wall))
			{
				JoinGeometryUtils.SwitchJoinOrder(this.m_doc, column, wall);
			}
		}

		private bool IsColumnLevelInWall(FamilyInstance column, Wall wall)
		{
			ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
			Level level = this.m_doc.GetElement(elementId) as Level;
			double num = wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
			double num2 = wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
			double num3 = level.Elevation + num;
			double value = num3 + num2;
			ElementId elementId2 = column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).AsElementId();
			Level level2 = this.m_doc.GetElement(elementId2) as Level;
			num = column.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).AsDouble();
			ElementId elementId3 = column.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).AsElementId();
			Level level3 = this.m_doc.GetElement(elementId3) as Level;
			num2 = column.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).AsDouble();
			double value2 = level2.Elevation + num;
			double value3 = level3.Elevation + num2;
			return (Math.Round(value2, 4) >= Math.Round(num3, 4) && Math.Round(value2, 4) < Math.Round(value, 4)) || (Math.Round(value3, 4) > Math.Round(num3, 4) && Math.Round(value3, 4) <= Math.Round(value, 4));
		}

		private ExternalCommandData m_cmdData;

		private Document m_doc;

		private Selection m_selection;

		public static WindowHandle _hWndRevit;

		private SortedList m_levels = new SortedList();
	}
}
